﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LINQtoLDAPDemo_Model;
using System.Windows;
using LinqToLdap;
using System.ComponentModel;
using GalaSoft.MvvmLight.Command;
using System.Windows.Input;
using System.Windows.Controls;

namespace LINQtoLDAPDemo_WPF
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private int _nonMemberPageNum, _memberPageNum, _totalNonMemberPages, _totalMemberPages, minPageNum = 1, pageSize = 10;
        private User[] _nonMembers, _members;
        private LinqToLdap.Collections.ILdapPage<User>[] nonMemberPages, memberPages;

        #region Commands
        public ICommand ChangeGroupCommand { get; private set; }
        public ICommand PreviousNonMemberPageCommand { get; private set; }
        public ICommand PreviousMemberPageCommand { get; private set; }
        public ICommand NextNonMemberPageCommand { get; private set; }
        public ICommand NextMemberPageCommand { get; private set; }
        #endregion

        #region Properties
        public Group[] Groups { get; set; }

        public User[] NonMembers
        {
            get
            {
                return _nonMembers;
            }
            set
            {
                _nonMembers = value;
                OnPropertyChanged("NonMembers");
            }
        }        

        public User[] Members
        {
            get
            {
                return _members;
            }
            set
            {
                _members = value;
                OnPropertyChanged("Members");
            }
        }

        public int NonMemberPageNum 
        {
            get { return _nonMemberPageNum; }
            set 
            {
                if (value >= minPageNum && value <= TotalNonMemberPages)
                {
                    _nonMemberPageNum = value;
                    UpdateView();
                }
                
                OnPropertyChanged("NonMemberPageNum"); 
            }
        }

        public int MemberPageNum 
        {
            get { return _memberPageNum; }
            set 
            {
                if (value >= minPageNum && value <= TotalMemberPages)
                {
                    _memberPageNum = value;
                    UpdateView();
                }

                OnPropertyChanged("MemberPageNum"); 
            }
        }

        public int TotalNonMemberPages 
        {
            get { return _totalNonMemberPages; }
            set { _totalNonMemberPages = value; OnPropertyChanged("TotalNonMemberPages"); }
        }

        public int TotalMemberPages
        {
            get { return _totalMemberPages; }
            set { _totalMemberPages = value; OnPropertyChanged("TotalMemberPages"); }
        }
        #endregion

        #region Constructor
        public MainWindowViewModel()
        {
            Groups = Group.GetAllGroups();
            TotalNonMemberPages = 1;
            TotalMemberPages = 1;
            NonMemberPageNum = 1;
            MemberPageNum = 1;

            // TODO: Do we really need four methods, one for each page button? Try to refactor and use command parameters.
            ChangeGroupCommand = new RelayCommand<Group>(ReloadViewData);
            PreviousNonMemberPageCommand = new RelayCommand(LoadPreviousNonMemberPage, () => NonMemberPageNum > 1);
            NextNonMemberPageCommand = new RelayCommand(LoadNextNonMemberPage, () => NonMemberPageNum < TotalNonMemberPages);
            PreviousMemberPageCommand = new RelayCommand(LoadPreviousMemberPage, () => MemberPageNum > 1);
            NextMemberPageCommand = new RelayCommand(LoadNextMemberPage, () => MemberPageNum < TotalMemberPages);
        }
        #endregion

        #region Events
        public void ReloadViewData(Group _group)
        {
            LoadUsers(_group);
            UpdateView();
        }
        
        public void AddUsersToGroup(Group _group, params User[] _users)
        {
            string[] userDNs = _users.Select(u => u.DistinguishedName).ToArray();

            _group.Members = _group.Members.Union(userDNs).ToArray();

            _group.Update();

            ReloadViewData(_group);
        }

        public void RemoveUsersFromGroup(Group _group, params User[] _users)
        {
            string[] userDNs = _users.Select(u => u.DistinguishedName).ToArray();

            _group.Members = _group.Members.Where(m => !userDNs.Contains(m)).Select(m => m).ToArray();

            _group.Update();

            ReloadViewData(_group);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion

        #region Private methods
        private void LoadPreviousNonMemberPage()
        {
            NonMemberPageNum--;
            NonMembers = nonMemberPages[NonMemberPageNum - 1].ToArray();
        }

        private void LoadNextNonMemberPage()
        {
            NonMemberPageNum++;
            NonMembers = nonMemberPages[NonMemberPageNum - 1].ToArray();
        }

        private void LoadPreviousMemberPage()
        {
            MemberPageNum--;
            Members = memberPages[MemberPageNum - 1].ToArray();
        }

        private void LoadNextMemberPage()
        {
            MemberPageNum++;
            Members = memberPages[MemberPageNum - 1].ToArray();
        }

        private void LoadUsers(Group _group)
        {
            nonMemberPages = Group.GetUserPagesByGroupMembershipStatus(_group, pageSize, false).ToArray();
            memberPages = Group.GetUserPagesByGroupMembershipStatus(_group, pageSize, true).ToArray();

            TotalNonMemberPages = nonMemberPages.Count();
            TotalMemberPages = memberPages.Count();
        }        
        
        private void UpdateView()
        {
            User[] _nonMembers;
            User[] _members;

            if (nonMemberPages != null && memberPages != null)
            {
                _nonMembers = nonMemberPages[NonMemberPageNum - 1].ToArray();
                _members = memberPages[MemberPageNum - 1].ToArray();
            }
            else
            {
                _nonMembers = new User[] { };
                _members = new User[] { };
            }

            NonMembers = _nonMembers;
            Members = _members;
        }
        #endregion
    }
}
